﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using Mvc4Demo.Extensions;

namespace Mvc4Demo.Controls
{
    public class SodaGrid
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="html"></param>
        /// <param name="columns"></param>
        /// <param name="rowsPerPage"></param>
        /// <param name="noOfFooterPageLinks"></param>
        public SodaGrid(IEnumerable<dynamic> model,
                        HtmlHelper html = null,
                        IEnumerable<SodaGridColumn> columns = null,
                        int rowsPerPage = 10,
                        int noOfFooterPageLinks = 5)
        {
            Model = model;
            Html = html;
            Columns = columns;
            RowsPerPage = rowsPerPage;
            NoOfFooterPageLinks = noOfFooterPageLinks;
        }

        /// <summary>
        /// Model
        /// </summary>
        public IEnumerable<dynamic> Model { get; private set; }

        public HtmlHelper Html { get; private set; }

        /// <summary>
        /// Total no. of pages
        /// </summary>
        public int PageCount
        {
            get { return TotalRowCount > 0 ? (int)Math.Ceiling((TotalRowCount / RowsPerPage)) : 0; }
        }

        /// <summary>
        /// get or set the current page.
        /// </summary>
        public int PageIndex { get; set; }

        /// <summary>
        /// get or set total no. of rows in the queue.
        /// </summary>
        public double TotalRowCount { get; set; }

        /// <summary>
        /// Total no. of rows par page.
        /// </summary>
        public double RowsPerPage { get; set; }

        /// <summary>
        /// No. of page links to display on the footer.
        /// </summary>
        public double NoOfFooterPageLinks { get; set; }

        /// <summary>
        /// show/hide edit button
        /// </summary>
        public bool ShowEditButton { get; set; }

        /// <summary>
        /// Show/hide delete button
        /// </summary>
        public bool ShowDeleteButton { get; set; }

        /// <summary>
        /// Show/hide Details button
        /// </summary>
        public bool ShowDetailsButton { get; set; }

        /// <summary>
        /// Show/hide Add button
        /// </summary>
        public bool ShowAddButton { get; set; }

        /// <summary>
        /// Show/hide search button
        /// </summary>
        public bool ShowSearchButton { get; set; }

        /// <summary>
        /// list of columns to display.
        /// </summary>
        public IEnumerable<SodaGridColumn> Columns { get; set; }

        /// <summary>
        /// Header CSS style
        /// </summary>
        public string HeaderStyle { get; set; }

        /// <summary>
        /// Footer CSS style
        /// </summary>
        public string FooterStyle { get; set; }

        /// <summary>
        /// First page link button CSS style
        /// </summary>
        public string FirstPageStyle { get; set; }
        /// <summary>
        /// Last page link button CSS style
        /// </summary>
        public string LastPageStyle { get; set; }
        /// <summary>
        /// Next page link button CSS style
        /// </summary>
        public string NextPageStyle { get; set; }
        /// <summary>
        /// Previous page link button CSS style
        /// </summary>
        public string PreviousPageStyle { get; set; }

        /// <summary>
        /// Header Formatter
        /// </summary>
        public Func<dynamic, object> HeaderFormat { get; set; }

        /// <summary>
        /// Footer Formatter
        /// </summary>
        public Func<object, object> FooterFormat { get; set; }

        public string SortColumn { get; private set; }
        public string SortDirection { get; private set; }

        public string SearchString { get; private set; }

        public string PreviousSortColumn { get; set; }
        public Dictionary<string, string> QueryString { get; private set; }

        /// <summary>
        /// generate HTML to render on page.
        /// </summary>
        /// <param name="tableStyle"></param>
        /// <param name="headerStyle"></param>
        /// <param name="footerStyle"></param>
        /// <param name="rowStyle"></param>
        /// <param name="alternatingRowStyle"></param>
        /// <param name="selectedRowStyle"></param>
        /// <param name="caption"></param>
        /// <param name="displayHeader"></param>
        /// <param name="fillEmptyRows"></param>
        /// <param name="emptyRowCellValue"></param>
        /// <returns></returns>
        public virtual IHtmlString GetHtml(string tableStyle = null, string headerStyle = null,
                                           string footerStyle = null, string rowStyle = null,
                                           string alternatingRowStyle = null, string selectedRowStyle = null,
                                           string caption = null, bool displayHeader = true, bool fillEmptyRows = false,
                                           string emptyRowCellValue = null)
        {
            SortColumn = HttpContext.Current.Request.QueryString[SodaConstants.SortParam];
            SortDirection = HttpContext.Current.Request.QueryString[SodaConstants.SortDirectionParam];

            BuildQueryString();

            GetPageIndex();

            //generate columns, if not declared
            if (Columns == null)
            {
                Columns = GenerateDataColumns();
            }

            var defaultColumns = CreateDefaultColumns();

            //merge default buttons with data columns
            var dataColumns = Columns.ToList();
            dataColumns.Insert(0, new SodaGridMultiFieldsColumn(defaultColumns));

            Columns = dataColumns;

            var searchBlock = new SodaGridSearch(this)
            {
                SearchText = SearchString
            };

            var headerBlock = new SodaGridHeader(this);
            var bodyBlock = new SodaGridBody(this);
            var footerBlock = new SodaGridFooter(this);

            var tableTag = CreateTagBuilder(SodaConstants.TableTag, tableStyle);

            //get row data
            var rowsHtml = bodyBlock.Render(rowStyle, alternatingRowStyle);

            var footerHtml = footerBlock.Render(footerStyle);

            //set header to table
            tableTag.InnerHtml = headerBlock.Render(headerStyle) + rowsHtml + footerHtml;

            return new MvcHtmlString(searchBlock.Render() + tableTag);
        }

        #region private and internal methods

        private void GetPageIndex()
        {
            var pageIndex = HttpContext.Current.Request.QueryString[SodaConstants.SortPageParam];

            if (!string.IsNullOrEmpty(pageIndex))
            {
                int result;
                if (int.TryParse(pageIndex, out result))
                {
                    PageIndex = result;
                }
            }
        }

        private void BuildQueryString()
        {
            var isPost = HttpContext.Current.Request.HttpMethod == "POST";

            SearchString = isPost
                               ? HttpContext.Current.Request.Form[SodaConstants.SearchStringParam]
                               : HttpContext.Current.Request[SodaConstants.SearchStringParam];

            QueryString = HttpContext.Current.Request.QueryString.Count > 0 && !isPost
                              ? HttpContext.Current.Request.QueryString
                                           .ToString()
                                           .Split('&').Select(x => new
                                           {
                                               Key = x.Split('=').First(),
                                               Value = x.Split('=').Last()
                                           }).ToDictionary(x => x.Key, x => x.Value)
                              : new Dictionary<string, string>();

            if (!string.IsNullOrEmpty(SearchString)
                && QueryString.All(x => x.Key != SodaConstants.SearchStringParam))
            {
                //add search text into query dictionary 
                QueryString.Add(SodaConstants.SearchStringParam, SearchString);
            }
            else if (string.IsNullOrEmpty(SearchString)
                     && QueryString.Any(x => x.Key == SodaConstants.SearchStringParam))
            {
                //remove if empty
                QueryString.Remove(SodaConstants.SearchStringParam);
            }
        }

        private IEnumerable<SodaGridColumn> CreateDefaultColumns()
        {
            var defaultColumns = new List<SodaGridColumn>();

            if (ShowDetailsButton)
            {
                defaultColumns.Add(new SodaGridColumn()
                {
                    Format = (item) => Html.ActionLink("Details", "Details", new { id = item.Id },
                                                       htmlAttributes: new { @class = "gridDetailsButton smallGridButton" })
                });
            }

            if (ShowEditButton)
            {
                defaultColumns.Add(new SodaGridColumn()
                {
                    Format = (item) => Html.ActionLink("Edit", "Edit", new { id = item.Id },
                                                       htmlAttributes: new { @class = "gridEditButton smallGridButton" })
                });
            }

            if (ShowDeleteButton)
            {
                defaultColumns.Add(new SodaGridColumn()
                {
                    Format = (item) => Html.ActionLink("Delete", "Delete", new { id = item.Id },
                                                       htmlAttributes: new { @class = "gridDeleteButton smallGridButton" })
                });
            }
            return defaultColumns;
        }

        private IEnumerable<SodaGridColumn> GenerateDataColumns()
        {
            var modelType = Model.GetType().GetGenericArguments()[0];

            return (from PropertyDescriptor property in TypeDescriptor.GetProperties(modelType)
                    select new SodaGridColumn(property.Name, property.DisplayName))
                .ToList();
        }

        internal static TagBuilder CreateTagBuilder(string tag,
                                                    string style = null,
                                                    string name = null,
                                                    string value = null,
                                                    string type = null)
        {
            var tagBuilder = new TagBuilder(tag);

            if (!string.IsNullOrEmpty(style))
            {
                tagBuilder.MergeAttribute(SodaConstants.ClassAttribute, style);
            }

            if (!string.IsNullOrEmpty(name))
            {
                tagBuilder.MergeAttribute(SodaConstants.NameAttribute, name);
            }

            if (!string.IsNullOrEmpty(value))
            {
                tagBuilder.MergeAttribute(SodaConstants.ValueAttribute, value);
            }

            if (!string.IsNullOrEmpty(type))
            {
                tagBuilder.MergeAttribute(SodaConstants.TypeAttribute, type);
            }

            return tagBuilder;
        }


        #endregion
    }

    internal class SodaGridSearch
    {
        internal const string SearchStr = "searchStr";
        internal const string AddButtonStyle = "gridAddButton";
        internal const string SearchButtonStyle = "gridSearchButton";
        internal const string SearchTextStyle = "gridSearchText";
        internal const string SearchCellStyle = "gridSearchCell";
        internal const string SearchTableStyle = "gridSearchTable";
        internal const string SearchButtonValue = "Search";

        private readonly SodaGrid _grid;

        internal SodaGridSearch(SodaGrid grid)
        {
            _grid = grid;
        }

        public string SearchText { get; set; }

        internal string Render()
        {
            var tableTag = SodaGrid.CreateTagBuilder(SodaConstants.TableTag, SearchTableStyle);
            var tbody = SodaGrid.CreateTagBuilder(SodaConstants.TableBodyTag);
            var trTag = SodaGrid.CreateTagBuilder(SodaConstants.TrTag);
            var addButtonCell = SodaGrid.CreateTagBuilder(SodaConstants.TdTag, SearchCellStyle);

            if (_grid.ShowAddButton)
            {
                addButtonCell.InnerHtml = _grid.Html.ActionLink(SodaConstants.CreateNew,
                                                                "Create", null,
                                                                htmlAttributes: new {@class = AddButtonStyle})
                                               .ToString();
            }

            var txtBoxCell = SodaGrid.CreateTagBuilder(SodaConstants.TdTag, SearchCellStyle);

            var buttonCell = SodaGrid.CreateTagBuilder(SodaConstants.TdTag, SearchCellStyle);

            if (_grid.ShowSearchButton)
            {
                txtBoxCell.InnerHtml = SodaGrid.CreateTagBuilder(SodaConstants.InputTag,
                                                                 name: SearchStr,
                                                                 style: SearchTextStyle,
                                                                 type: SodaConstants.TypeText,
                                                                 value: SearchText)
                                               .ToString();


                buttonCell.InnerHtml = SodaGrid.CreateTagBuilder(SodaConstants.InputTag,
                                                                 type: SodaConstants.TypeSubmit,
                                                                 style: SearchButtonStyle,
                                                                 value: SearchButtonValue)
                                               .ToString();
            }

            trTag.InnerHtml = addButtonCell + txtBoxCell.ToString() + buttonCell;
            tbody.InnerHtml = trTag.ToString();
            tableTag.InnerHtml = tbody.ToString();
            return tableTag.ToString();
        }
    }

    public class SodaGridColumn
    {
        public SodaGridColumn(string columnName = null,
                              string header = null,
                              Func<dynamic, string> format = null,
                              string style = null,
                              string headerStyle = null,
                              bool canSort = true)
        {
            HeaderStyle = headerStyle;
            CanSort = canSort;
            Style = style;
            ColumnName = columnName;
            Header = header;
            Format = format;
        }

        /// <summary>
        /// Column name
        /// </summary>
        public string ColumnName { get; private set; }

        public string Header { get; set; }

        public Func<dynamic, object> Format { get; set; }

        public string Style { get; set; }

        public string HeaderStyle { get; set; }

        public bool CanSort { get; set; }

        public virtual string Render(SodaGrid grid, dynamic model = null, bool header = false)
        {
            return header ? RenderHeader(grid) : RenderData(grid, model);
        }

        protected virtual string RenderData(SodaGrid grid, dynamic model)
        {
            var dataCell = SodaGrid.CreateTagBuilder(SodaConstants.TdTag, Style);
            //set empty if not format or ColumnName available

            if (Format == null)
            {
                dataCell.InnerHtml = !string.IsNullOrEmpty(ColumnName)
                                         ? model[ColumnName].ToString()
                                         : string.Empty;
            }
            else
            {
                var formattedValue = Format(model);
                dataCell.InnerHtml = formattedValue == null ? string.Empty : formattedValue.ToString();
            }

            return dataCell.ToString();
        }

        protected virtual string RenderHeader(SodaGrid grid)
        {
            var headerText = Header ?? ColumnName;

            var tagBuilder = SodaGrid.CreateTagBuilder(SodaConstants.ThTag,
                                                       HeaderStyle ?? grid.HeaderStyle);
            tagBuilder.MergeAttribute("scope", "col");

            if (!string.IsNullOrEmpty(headerText))
            {
                var formatedHeaderText = grid.HeaderFormat != null
                                             ? grid.HeaderFormat(headerText).ToString()
                                             : headerText;

                if (CanSort)
                {
                    var ancherBuilder = new TagBuilder(SodaConstants.AncherTag);

                    var sortDirection = SodaConstants.SortAscParam;

                    if (grid.SortColumn == ColumnName)
                    {
                        sortDirection = grid.SortDirection == SodaConstants.SortDescParam
                                            ? SodaConstants.SortAscParam
                                            : SodaConstants.SortDescParam;

                        var appiledSortClass = grid.SortDirection == SodaConstants.SortDescParam
                                                   ? "gridSortDescColumn"
                                                   : "gridSortAscColumn";

                        var sortSpanTagBuilder = SodaGrid.CreateTagBuilder(SodaConstants.SpanTag, appiledSortClass);
                        sortSpanTagBuilder.InnerHtml = "&nbsp;&nbsp;&nbsp;";

                        formatedHeaderText += sortSpanTagBuilder;

                    }
                    var queryStrings = grid.QueryString
                                           .Where(x =>
                                                  x.Key != SodaConstants.SortParam &&
                                                  x.Key != SodaConstants.SortDirectionParam)
                                           .ToDictionary(x => x.Key, x => x.Value);

                    queryStrings.Add(SodaConstants.SortParam, ColumnName);
                    queryStrings.Add(SodaConstants.SortDirectionParam, sortDirection);

                    var hrefValue = queryStrings.Select(x => string.Format("{0}={1}", x.Key, x.Value))
                                                .Aggregate((c, n) => string.Format("{0}&{1}", c, n));

                    ancherBuilder.MergeAttribute(SodaConstants.HrefAttribute,
                                                 string.Format("?{0}", hrefValue));

                    ancherBuilder.InnerHtml = formatedHeaderText;

                    tagBuilder.InnerHtml = ancherBuilder.ToString();
                }
                else
                {
                    tagBuilder.InnerHtml = formatedHeaderText;
                }
            }

            return tagBuilder.ToString();
        }
    }

    public class SodaGridMultiFieldsColumn : SodaGridColumn
    {
        private readonly IEnumerable<SodaGridColumn> _childColumns;

        public SodaGridMultiFieldsColumn(IEnumerable<SodaGridColumn> childColumns,
                                         string columnName = null,
                                         string header = null,
                                         string style = null,
                                         string headerStyle = null,
                                         bool canSort = false)
            : base(columnName, header, null, style, headerStyle, canSort)
        {
            _childColumns = childColumns;
            Format = (item) => _childColumns.Aggregate(string.Empty,
                                                       (cur, next) =>
                                                       cur + next.Format(item).ToString());
        }
    }

    internal class SodaGridHeader
    {
        private readonly SodaGrid _grid;

        internal SodaGridHeader(SodaGrid grid)
        {
            _grid = grid;
        }

        internal string Render(string headerStyle = null)
        {
            var headerBuilder = SodaGrid.CreateTagBuilder(SodaConstants.TableHeaderTag);
            var headerRowBuilder = SodaGrid.CreateTagBuilder(SodaConstants.TrTag, headerStyle);

            var headerCells = GetHeaderCells();

            //set header cells to header row
            headerRowBuilder.InnerHtml = headerCells;

            headerBuilder.InnerHtml = headerRowBuilder.ToString();

            return headerBuilder.ToString();
        }


        private string GetHeaderCells()
        {
            var sbHeaderCells = new StringBuilder();

            foreach (var column in _grid.Columns)
            {
                sbHeaderCells.Append(column.Render(_grid, header: true));
            }

            return sbHeaderCells.ToString();
        }
    }

    internal class SodaGridBody
    {
        private readonly SodaGrid _grid;

        public SodaGridBody(SodaGrid grid)
        {
            _grid = grid;
        }

        internal string Render(string rowStyle = null, string alternatingRowStyle = null)
        {
            var sbRowsData = new StringBuilder();

            var rowCount = 0;
            foreach (var modelObject in _grid.Model)
            {
                var modelRow = DynamicExtensions.ToDynamic(modelObject);

                //generate row
                var sbRowData = new StringBuilder();

                //set style
                string style = null;
                if (!string.IsNullOrEmpty(rowStyle))
                {
                    style = !string.IsNullOrEmpty(alternatingRowStyle) && rowCount % 2 == 0
                                ? rowStyle
                                : alternatingRowStyle;

                }

                var rowTagBuilder = SodaGrid.CreateTagBuilder(SodaConstants.TrTag, style);

                //generate cells
                foreach (var column in _grid.Columns)
                {
                    sbRowData.Append(column.Render(_grid, modelRow));
                }

                rowTagBuilder.InnerHtml = sbRowData.ToString();
                sbRowsData.Append(rowTagBuilder);
                rowCount++;
            }

            return sbRowsData.ToString();
        }
    }

    internal class SodaGridFooter
    {
        private readonly SodaGrid _grid;

        public SodaGridFooter(SodaGrid grid)
        {
            _grid = grid;
        }

        public int PageCount { get { return _grid.PageCount; } }
        public double NoOfFooterPageLinks { get { return _grid.NoOfFooterPageLinks; } }

        public IEnumerable<PageLink> PageLinks { get; private set; }


        internal string Render(string footerStyle = null)
        {
            PageLinks = GeneratePageLinks();

            var tfootTagBuilder = new TagBuilder(SodaConstants.TableFooterTag);

            var rowTagBuilder = SodaGrid.CreateTagBuilder(SodaConstants.TrTag, footerStyle);

            var cellTagBuilder = new TagBuilder(SodaConstants.TdTag);

            cellTagBuilder.MergeAttribute("colspan", _grid.Columns.Count().ToString());

            var sbRowData = new StringBuilder();

            foreach (var pageLink in PageLinks)
            {
                sbRowData.Append(pageLink.Render());
            }

            var recordCountTagBuilder = SodaGrid.CreateTagBuilder(SodaConstants.SpanTag, "gridRecordCount");
            recordCountTagBuilder.InnerHtml = string.Format("Total Records : {0}", _grid.TotalRowCount);

            cellTagBuilder.InnerHtml = sbRowData.ToString() + recordCountTagBuilder;
            rowTagBuilder.InnerHtml = cellTagBuilder.ToString();

            tfootTagBuilder.InnerHtml = rowTagBuilder.ToString();

            return tfootTagBuilder.ToString();
        }

        #region private methods

        private IEnumerable<PageLink> GeneratePageLinks()
        {
            var pageLinks = new List<PageLink>();

            var firstPageLink = CreatePageLink("|<", "gridFirstPage");
            var lastPageLink = CreatePageLink(">|", "gridLastPage");
            var nextPageLink = CreatePageLink(">", "gridNextPage");
            var prevPageLink = CreatePageLink("<", "gridPrevPage");

            //add first page & previous page link
            pageLinks.Add(firstPageLink);
            pageLinks.Add(prevPageLink);

            if (PageCount > 0)
            {
                if (_grid.PageIndex <= 1)
                {
                    _grid.PageIndex = 1;
                    firstPageLink.PageNo = -1;
                    prevPageLink.PageNo = -1;
                }
                else if (_grid.PageIndex >= PageCount)
                {
                    _grid.PageIndex = PageCount;
                    nextPageLink.PageNo = -1;
                    lastPageLink.PageNo = -1;
                }

                if (_grid.PageIndex >= 1 && _grid.PageIndex < PageCount)
                {
                    nextPageLink.PageNo = _grid.PageIndex + 1;
                    lastPageLink.PageNo = PageCount;
                }
                if (_grid.PageIndex > 1 && _grid.PageIndex <= PageCount)
                {
                    firstPageLink.PageNo = 1;
                    prevPageLink.PageNo = _grid.PageIndex - 1;
                }

                var startPage = 1;
                if (NoOfFooterPageLinks < PageCount)
                {
                    if (_grid.PageIndex != PageCount)
                    {
                        //find middle page, if it's lat page then add 1 extra
                        var middlePage = (int)Math.Ceiling((NoOfFooterPageLinks / 2));
                        startPage = Math.Max(1, _grid.PageIndex - middlePage);
                    }
                    else
                    {
                        startPage = (int)(PageCount - NoOfFooterPageLinks) + 1;
                    }
                }

                var endPage = Math.Min((startPage + NoOfFooterPageLinks - 1), PageCount);

                for (var i = startPage; i <= endPage; i++)
                {
                    pageLinks.Add(new PageLink(_grid)
                    {
                        Selected = _grid.PageIndex == i,
                        PageNo = _grid.PageIndex == i ? -1 : i,
                        Text = i.ToString(),
                        Style = "gridLinkPage"
                    });
                }
            }

            //add first next & last page link
            pageLinks.Add(nextPageLink);
            pageLinks.Add(lastPageLink);
            return pageLinks;
        }

        private PageLink CreatePageLink(string text, string style)
        {
            return new PageLink(_grid)
            {
                PageNo = -1,
                Style = "gridLinkPage" + (!string.IsNullOrEmpty(style) ? string.Format(" {0}", style) : ""),
                Text = text
            };
        }
        #endregion
    }

    public class PageLink
    {
        private readonly SodaGrid _grid;

        public PageLink(SodaGrid grid)
        {
            _grid = grid;
        }

        public int PageNo { get; set; }

        public string Style { get; set; }

        public string Text { get; set; }

        public bool Selected { get; set; }

        public virtual string Render()
        {
            var linkPageBuilderTag = PageNo > 0 ? SodaConstants.AncherTag : SodaConstants.DivTag;
            var linkPageBuilderStyle = Selected ? "gridPageSelected" : Style;

            var linkTagBuilder = SodaGrid.CreateTagBuilder(linkPageBuilderTag, linkPageBuilderStyle);

            var linkText = Text ?? PageNo.ToString();

            linkTagBuilder.InnerHtml = _grid.FooterFormat != null
                                          ? _grid.FooterFormat(linkText).ToString()
                                          : linkText;

            if (PageNo > 0)
            {
                var queryStrings = _grid.QueryString
                                      .Where(x => x.Key != SodaConstants.SortPageParam)
                                      .ToDictionary(x => x.Key, x => x.Value);

                queryStrings.Add(SodaConstants.SortPageParam, PageNo.ToString());

                var hrefValue = queryStrings.Select(x => string.Format("{0}={1}", x.Key, x.Value))
                                            .Aggregate((c, n) => string.Format("{0}&{1}", c, n));

                linkTagBuilder.MergeAttribute(SodaConstants.HrefAttribute, string.Format("?{0}", hrefValue));
            }
            return linkTagBuilder.ToString();
        }
    }

    internal static class SodaConstants
    {
        internal const string DivTag = "div";
        internal const string AncherTag = "a";
        internal const string SpanTag = "span";
        internal const string TableTag = "table";
        internal const string TableHeaderTag = "thead";
        internal const string TableFooterTag = "tfoot";
        internal const string TableBodyTag = "tbody";
        internal const string TrTag = "tr";
        internal const string TdTag = "td";
        internal const string ThTag = "th";

        internal const string InputTag = "input";

        internal const string ClassAttribute = "class";
        internal const string NameAttribute = "name";
        internal const string ValueAttribute = "value";
        internal const string TypeAttribute = "type";
        internal const string TypeText = "text";
        internal const string TypeSubmit = "submit";
        internal const string HrefAttribute = "href";

        internal const string SortParam = "sort";
        internal const string SortDirectionParam = "sortdir";

        internal const string SortDescParam = "DESC";
        internal const string SortAscParam = "ASC";
        internal const string SortPageParam = "page";
        internal const string SearchStringParam = "searchStr";

        internal const string CreateNew = "Create New";
    }
}